package io.github.bluesbruce.client;

import io.github.bluesbruce.commons.Constant;
import io.github.bluesbruce.commons.TransferFile;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import java.io.IOException;
import java.io.RandomAccessFile;
import org.apache.commons.io.FileUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * Netty客户端处理程序
 *
 * @author BBF
 */
public class DolphinClientHandler extends ChannelInboundHandlerAdapter {

  private static final Logger LOGGER = LoggerFactory.getLogger(DolphinClientHandler.class);
  private final TransferFile file;
  private RandomAccessFile randomAccessFile = null;
  private long fileSize = 0L;
  private long startTime = 0L;

  DolphinClientHandler(TransferFile file) {
    this.file = file;
  }

  @Override
  public void channelInactive(ChannelHandlerContext ctx) throws Exception {
    super.channelInactive(ctx);
    if (randomAccessFile != null) {
      randomAccessFile.close();
    }
    if (LOGGER.isDebugEnabled()) {
      float time = (System.currentTimeMillis() - this.startTime) / 1000.0F;
      LOGGER.debug("====传输完毕，共计{}，耗时={} s，速度={} kb/s",
          FileUtils.byteCountToDisplaySize(fileSize), time, fileSize / time / 1024.0F);
    }
  }

  @Override
  public void channelActive(ChannelHandlerContext ctx) throws IOException {
    // 只读方式打开要上传的文件，在通道Inactive时，关闭文件
    this.randomAccessFile = new RandomAccessFile(file.getFile(), Constant.FILE_READ);
    this.fileSize = randomAccessFile.length();
    if (LOGGER.isDebugEnabled()) {
      this.startTime = System.currentTimeMillis();
      LOGGER.debug("====数据通道建立，{}", ctx.channel().remoteAddress());
    }
    // 发送文件的md5到服务端，验证是否秒传
    ctx.channel().writeAndFlush(file.getMd5());
  }

  @Override
  public void channelRead(ChannelHandlerContext ctx, Object msg)
      throws Exception {
    if (msg instanceof Integer) {
      // 接收服务器发送的偏移量
      int start = (Integer) msg;
      if (Constant.TRANSMIT_MD5_EXISTS == start) {
        if (LOGGER.isDebugEnabled()) {
          LOGGER.debug("====文件秒传完毕，{}", file.getFile().toURI());
        }
        ctx.close();
      } else if (start >= Constant.TRANSMIT_START) {
        // 设置读文件的起始点
        file.setStarPos(start);
        randomAccessFile.seek(start);
        // 剩余未读的字节长度
        long remaining = fileSize - start;
        remaining = remaining > 0 ? remaining : 0;
        byte[] bytes;
        if (remaining > Constant.SEND_SIZE) {
          bytes = new byte[Constant.SEND_SIZE];
        } else {
          // 剩余部分不足单次发送数据长度，则将剩余部分全部发送，也就意味着这是最后一部分数据。
          bytes = new byte[(int) remaining];
        }
        int byteRead;
        if (remaining > 0 && (byteRead = randomAccessFile.read(bytes)) != -1) {
          file.setEndPos(byteRead);
          file.setBytes(bytes);
          ctx.writeAndFlush(file);
        } else {
          randomAccessFile.close();
          ctx.close();
          if (LOGGER.isDebugEnabled()) {
            LOGGER.debug("====文件传输完毕，{}", file.getFile().toURI());
          }
        }
      }
    }
  }

  @Override
  public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
    ctx.close();
    cause.printStackTrace();
  }
}
